package net.chenlin.dp.modules.socket;


import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Yangsm
 * @ClassName: Server
 * @Description: TODO
 * @date 2022年11月10日 20:59
 */
@Slf4j
public class SocketServer {

    /**
     * 要处理客户端发来的对象，并返回一个对象，可实现该接口。
     */
    public interface ObjectAction{
        Object doAction(Object rev, SocketServer server);
    }

    public static final class DefaultObjectAction implements ObjectAction{
        @Override
        public Object doAction(Object rev, SocketServer server) {
            System.out.println("Server返回发送给Client的消息："+rev);
            return rev;
        }
    }

    public static void main(String[] args) {
        int port = 10003;
        SocketServer server = new SocketServer(port);
        server.start();
    }

    private int port;

    private volatile boolean running=false;

    private long receiveTimeDelay=10000;

    private ConcurrentHashMap<Class, ObjectAction> actionMapping = new ConcurrentHashMap<Class,ObjectAction>();

    private Thread connWatchDog;

    public SocketServer(int port) {
        this.port = port;
    }

    public void start(){
        if(running) {
            return;
        }
        running=true;
        connWatchDog = new Thread(new ConnWatchDog());
        connWatchDog.start();
        System.out.println("Server服务端启动成功");
    }

    @SuppressWarnings("deprecation")
    public void stop(){
        if(running) {
            running=false;
        }
        if(connWatchDog!=null) {
            connWatchDog.stop();
        }
    }

    public void addActionMap(Class<Object> cls,ObjectAction action){
        actionMapping.put(cls, action);
    }

    class ConnWatchDog implements Runnable{

        @Override
        public void run(){
            System.out.println("ConnWatchDog的run方法。。。。。。");
            try {
                ServerSocket ss = new ServerSocket(port,5);
                while(running){

                    System.out.println("客户端来消息了. . .");
                    //连接请求队列中取出一个客户的连接请求，然后创建与客户连接的Socket对象，并将它返回。
                    // 如果队列中没有连接请求，accept()方法就会一直等待，直到接收到了连接请求才返回
                    Socket clientSocket = ss.accept();
                    log.info("=== 有客户端连上服务端, 客户端信息如下：" + clientSocket.getInetAddress() + " : " + clientSocket.getPort() + ".");

                    InputStream inputStream = clientSocket.getInputStream();

                    byte[] by = new byte[1024];
                    int len=inputStream.read(by);
                    String data = new String(by,0,len);
                    System.out.println("客户端发来的消息是：== "+data);

                }
            } catch (Exception e) {
                e.printStackTrace();
                SocketServer.this.stop();
            }

        }
    }

    class SocketAction implements Runnable{
        Socket s;
        boolean run=true;
        long lastReceiveTime = System.currentTimeMillis();
        public SocketAction(Socket s) {
            this.s = s;
        }
        @Override
        public void run() {
            while(running && run){
                if(System.currentTimeMillis()-lastReceiveTime>receiveTimeDelay){
                    overThis();
                }else{
                    try {
                        System.out.println("==== 进来了，获取Client端发送过来的消息");
                        InputStream in = s.getInputStream();
                        if(in.available()>0){
                            System.out.println("进来获取流的数据。。。。");
                            ObjectInputStream ois = new ObjectInputStream(in);
                            Object obj = ois.readObject();
                            lastReceiveTime = System.currentTimeMillis();
                            System.out.println(" Client端发送过来的消息：\t"+obj);
                            ObjectAction oa = actionMapping.get(obj.getClass());
                            oa = oa==null?new DefaultObjectAction():oa;
                            String receive = "我在的，千万不要掉线哦。。。。。。。";
                            Object out = oa.doAction(receive, SocketServer.this);
                            if(out!=null){
                                ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
                                oos.writeObject(out);
                                oos.flush();
                            }
                        }else{
                            Thread.sleep(10);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        System.out.println(" 127下面的overThis");
                        overThis();
                    }
                }
            }
        }

        private void overThis() {
            if(run) {
                run=false;
            }
            if(s!=null){
                try {
                    s.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("关闭："+s.getRemoteSocketAddress());
        }

    }
}
